"""
Chart Generator Module for xlcig Notebook Visualization Platform
Supports multiple chart types and themes using matplotlib, seaborn, plotly, and ECharts
"""

import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
import pandas as pd
import numpy as np
import io
import base64
from typing import Optional, Dict, Any, Tuple, List
import plotly.express as px
import plotly.graph_objects as go
from plotly.offline import plot
import plotly
import json


class ChartGenerator:
    """Generates various types of charts with different themes and ECharts support"""
    
    def __init__(self):
        self.themes = {
            'default': 'default',
            'seaborn': 'seaborn-v0_8',
            'ggplot': 'ggplot',
            'bmh': 'bmh'
        }
        
        self.chart_types = [
            'line', 'bar', 'scatter', 'heatmap', 'histogram', 'box', 'pie', 'radar', 'funnel'
        ]
        
        # Set default matplotlib parameters
        plt.rcParams['figure.figsize'] = (10, 6)
        plt.rcParams['font.size'] = 10
        plt.rcParams['axes.grid'] = True
        plt.rcParams['grid.alpha'] = 0.3
        
        # Set Chinese font support
        try:
            # Try common Chinese fonts
            import platform
            if platform.system() == 'Windows':
                plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'SimSun']
            else:
                plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'Liberation Sans', 'Arial']
            plt.rcParams['axes.unicode_minus'] = False  # Fix minus sign display
        except:
            pass
    
    def generate_echarts_config(self, 
                               df: pd.DataFrame, 
                               chart_type: str, 
                               x_col: Optional[str] = None, 
                               y_col: Optional[str] = None, 
                               title: str = '',
                               theme: str = 'default') -> Dict[str, Any]:
        """
        Generate ECharts configuration for frontend rendering
        
        Args:
            df: Input DataFrame
            chart_type: Type of chart to generate
            x_col: Column for x-axis
            y_col: Column for y-axis
            title: Chart title
            theme: Chart theme
            
        Returns:
            ECharts configuration dictionary
        """
        try:
            if chart_type == 'line':
                return self._create_line_echarts(df, x_col, y_col, title)
            elif chart_type == 'bar':
                return self._create_bar_echarts(df, x_col, y_col, title)
            elif chart_type == 'scatter':
                return self._create_scatter_echarts(df, x_col, y_col, title)
            elif chart_type == 'pie':
                return self._create_pie_echarts(df, x_col, y_col, title)
            elif chart_type == 'heatmap':
                return self._create_heatmap_echarts(df, title)
            elif chart_type == 'histogram':
                return self._create_histogram_echarts(df, x_col, title)
            elif chart_type == 'radar':
                return self._create_radar_echarts(df, title)
            elif chart_type == 'funnel':
                return self._create_funnel_echarts(df, x_col, y_col, title)
            else:
                raise ValueError(f"Unsupported chart type: {chart_type}")
                
        except Exception as e:
            return {
                'error': True,
                'message': str(e),
                'title': {'text': f'Error: {title}'}
            }
    
    def _create_line_echarts(self, df: pd.DataFrame, x_col: str, y_col: str, title: str) -> Dict:
        """Create ECharts line chart configuration"""
        try:
            # Prepare data
            if x_col and y_col:
                x_data = df[x_col].tolist()
                y_data = df[y_col].tolist()
            else:
                # Use index and first numeric column
                numeric_cols = df.select_dtypes(include=[np.number]).columns
                if len(numeric_cols) > 0:
                    x_data = df.index.tolist()
                    y_data = df[numeric_cols[0]].tolist()
                else:
                    x_data = []
                    y_data = []
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'axis',
                    'axisPointer': {'type': 'cross'}
                },
                'legend': {
                    'bottom': 10
                },
                'grid': {
                    'left': '3%',
                    'right': '4%',
                    'bottom': '15%',
                    'containLabel': True
                },
                'xAxis': {
                    'type': 'category',
                    'data': x_data,
                    'name': x_col or 'Index'
                },
                'yAxis': {
                    'type': 'value',
                    'name': y_col or 'Value'
                },
                'series': [{
                    'name': y_col or 'Value',
                    'type': 'line',
                    'data': y_data,
                    'smooth': True,
                    'symbol': 'circle',
                    'symbolSize': 6,
                    'lineStyle': {'width': 3},
                    'areaStyle': {'opacity': 0.1}
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_bar_echarts(self, df: pd.DataFrame, x_col: str, y_col: str, title: str) -> Dict:
        """Create ECharts bar chart configuration"""
        try:
            # Prepare data
            if x_col and y_col:
                if df[x_col].dtype == 'object':
                    # Group categorical data
                    grouped = df.groupby(x_col)[y_col].mean().head(20)  # Top 20 categories
                    x_data = grouped.index.tolist()
                    y_data = grouped.values.tolist()
                else:
                    x_data = df[x_col].head(50).tolist()
                    y_data = df[y_col].head(50).tolist()
            else:
                # Use first two columns
                cols = df.columns.tolist()
                if len(cols) >= 2:
                    x_data = df[cols[0]].head(20).tolist()
                    y_data = df[cols[1]].head(20).tolist()
                else:
                    x_data = []
                    y_data = []
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'axis',
                    'axisPointer': {'type': 'shadow'}
                },
                'grid': {
                    'left': '3%',
                    'right': '4%',
                    'bottom': '15%',
                    'containLabel': True
                },
                'xAxis': {
                    'type': 'category',
                    'data': x_data,
                    'name': x_col or 'Category',
                    'axisLabel': {'rotate': 45}
                },
                'yAxis': {
                    'type': 'value',
                    'name': y_col or 'Value'
                },
                'series': [{
                    'name': y_col or 'Value',
                    'type': 'bar',
                    'data': y_data,
                    'itemStyle': {
                        'color': {
                            'type': 'linear',
                            'x': 0, 'y': 0, 'x2': 0, 'y2': 1,
                            'colorStops': [
                                {'offset': 0, 'color': '#83bff6'},
                                {'offset': 0.5, 'color': '#188df0'},
                                {'offset': 1, 'color': '#188df0'}
                            ]
                        }
                    },
                    'emphasis': {
                        'itemStyle': {'color': '#12c2e9'}
                    }
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_scatter_echarts(self, df: pd.DataFrame, x_col: str, y_col: str, title: str) -> Dict:
        """Create ECharts scatter plot configuration"""
        try:
            # Sample data if too large
            sample_df = df.sample(min(1000, len(df))) if len(df) > 1000 else df
            
            if x_col and y_col:
                # Remove null values
                clean_df = sample_df.dropna(subset=[x_col, y_col])
                data = [[row[x_col], row[y_col]] for _, row in clean_df.iterrows()]
            else:
                # Use first two numeric columns
                numeric_cols = sample_df.select_dtypes(include=[np.number]).columns
                if len(numeric_cols) >= 2:
                    clean_df = sample_df.dropna(subset=[numeric_cols[0], numeric_cols[1]])
                    data = [[row[numeric_cols[0]], row[numeric_cols[1]]] for _, row in clean_df.iterrows()]
                    x_col = numeric_cols[0]
                    y_col = numeric_cols[1]
                else:
                    data = []
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'item',
                    'formatter': '{b0}: {c0}<br/>{b1}: {c1}'
                },
                'grid': {
                    'left': '3%',
                    'right': '7%',
                    'bottom': '15%',
                    'containLabel': True
                },
                'xAxis': {
                    'type': 'value',
                    'name': x_col or 'X',
                    'scale': True,
                    'axisLabel': {'formatter': '{value}'}
                },
                'yAxis': {
                    'type': 'value',
                    'name': y_col or 'Y',
                    'scale': True,
                    'axisLabel': {'formatter': '{value}'}
                },
                'series': [{
                    'name': f'{x_col} vs {y_col}',
                    'type': 'scatter',
                    'data': data,
                    'symbolSize': 8,
                    'itemStyle': {
                        'color': '#c23531',
                        'opacity': 0.7
                    },
                    'emphasis': {
                        'itemStyle': {'color': '#e83c3c', 'opacity': 1}
                    }
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_pie_echarts(self, df: pd.DataFrame, x_col: str, y_col: str, title: str) -> Dict:
        """Create ECharts pie chart configuration"""
        try:
            if x_col and y_col:
                # Group by x_col and sum y_col
                grouped = df.groupby(x_col)[y_col].sum().head(10)  # Top 10 categories
                data = [{'name': str(name), 'value': float(value)} for name, value in grouped.items()]
            else:
                # Use value counts of first categorical column
                cat_cols = df.select_dtypes(include=['object']).columns
                if len(cat_cols) > 0:
                    value_counts = df[cat_cols[0]].value_counts().head(10)
                    data = [{'name': str(name), 'value': int(value)} for name, value in value_counts.items()]
                else:
                    data = []
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'item',
                    'formatter': '{a} <br/>{b}: {c} ({d}%)'
                },
                'legend': {
                    'bottom': 10,
                    'left': 'center'
                },
                'series': [{
                    'name': y_col or 'Count',
                    'type': 'pie',
                    'radius': ['40%', '70%'],
                    'center': ['50%', '45%'],
                    'avoidLabelOverlap': False,
                    'itemStyle': {
                        'borderRadius': 10,
                        'borderColor': '#fff',
                        'borderWidth': 2
                    },
                    'label': {
                        'show': False,
                        'position': 'center'
                    },
                    'emphasis': {
                        'label': {
                            'show': True,
                            'fontSize': '16',
                            'fontWeight': 'bold'
                        }
                    },
                    'labelLine': {'show': False},
                    'data': data
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_heatmap_echarts(self, df: pd.DataFrame, title: str) -> Dict:
        """Create ECharts heatmap configuration"""
        try:
            # Calculate correlation matrix
            numeric_df = df.select_dtypes(include=[np.number])
            if numeric_df.empty:
                return {'error': True, 'message': 'No numeric columns for heatmap'}
            
            corr_matrix = numeric_df.corr()
            
            # Prepare data for ECharts
            data = []
            for i, row_name in enumerate(corr_matrix.index):
                for j, col_name in enumerate(corr_matrix.columns):
                    data.append([i, j, round(corr_matrix.iloc[i, j], 3)])
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'position': 'top',
                    'formatter': '{b}: {c}'
                },
                'grid': {
                    'height': '50%',
                    'top': '10%'
                },
                'xAxis': {
                    'type': 'category',
                    'data': corr_matrix.columns.tolist(),
                    'splitArea': {'show': True},
                    'axisLabel': {'rotate': 45}
                },
                'yAxis': {
                    'type': 'category',
                    'data': corr_matrix.index.tolist(),
                    'splitArea': {'show': True}
                },
                'visualMap': {
                    'min': -1,
                    'max': 1,
                    'calculable': True,
                    'orient': 'horizontal',
                    'left': 'center',
                    'bottom': '5%',
                    'inRange': {
                        'color': ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', 
                                 '#ffffcc', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
                    }
                },
                'series': [{
                    'name': 'Correlation',
                    'type': 'heatmap',
                    'data': data,
                    'label': {
                        'show': True,
                        'fontSize': 10
                    },
                    'emphasis': {
                        'itemStyle': {
                            'shadowBlur': 10,
                            'shadowColor': 'rgba(0, 0, 0, 0.5)'
                        }
                    }
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_histogram_echarts(self, df: pd.DataFrame, x_col: str, title: str) -> Dict:
        """Create ECharts histogram configuration"""
        try:
            if x_col:
                data = df[x_col].dropna()
            else:
                numeric_cols = df.select_dtypes(include=[np.number]).columns
                if len(numeric_cols) > 0:
                    data = df[numeric_cols[0]].dropna()
                    x_col = numeric_cols[0]
                else:
                    return {'error': True, 'message': 'No numeric column for histogram'}
            
            # Create histogram bins
            counts, bins = np.histogram(data, bins=30)
            bin_centers = [(bins[i] + bins[i+1]) / 2 for i in range(len(bins)-1)]
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'axis',
                    'axisPointer': {'type': 'shadow'}
                },
                'grid': {
                    'left': '3%',
                    'right': '4%',
                    'bottom': '15%',
                    'containLabel': True
                },
                'xAxis': {
                    'type': 'category',
                    'data': [f'{x:.2f}' for x in bin_centers],
                    'name': x_col
                },
                'yAxis': {
                    'type': 'value',
                    'name': 'Frequency'
                },
                'series': [{
                    'name': 'Frequency',
                    'type': 'bar',
                    'data': counts.tolist(),
                    'itemStyle': {
                        'color': {
                            'type': 'linear',
                            'x': 0, 'y': 0, 'x2': 0, 'y2': 1,
                            'colorStops': [
                                {'offset': 0, 'color': '#ffecd2'},
                                {'offset': 1, 'color': '#fcb69f'}
                            ]
                        }
                    }
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_radar_echarts(self, df: pd.DataFrame, title: str) -> Dict:
        """Create ECharts radar chart configuration"""
        try:
            # Use numeric columns for radar chart
            numeric_cols = df.select_dtypes(include=[np.number]).columns[:6]  # Max 6 dimensions
            if len(numeric_cols) < 3:
                return {'error': True, 'message': 'Need at least 3 numeric columns for radar chart'}
            
            # Normalize data to 0-100 scale
            normalized_df = df[numeric_cols].copy()
            for col in numeric_cols:
                min_val = normalized_df[col].min()
                max_val = normalized_df[col].max()
                if max_val != min_val:
                    normalized_df[col] = ((normalized_df[col] - min_val) / (max_val - min_val)) * 100
                else:
                    normalized_df[col] = 50
            
            # Take first few rows as series
            series_data = []
            for i, (idx, row) in enumerate(normalized_df.head(5).iterrows()):
                series_data.append({
                    'value': row.tolist(),
                    'name': f'Sample {i+1}'
                })
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'item'
                },
                'legend': {
                    'bottom': 10,
                    'left': 'center'
                },
                'radar': {
                    'indicator': [{'name': col, 'max': 100} for col in numeric_cols],
                    'center': ['50%', '50%'],
                    'radius': '70%'
                },
                'series': [{
                    'name': 'Sample Data',
                    'type': 'radar',
                    'data': series_data
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_funnel_echarts(self, df: pd.DataFrame, x_col: str, y_col: str, title: str) -> Dict:
        """Create ECharts funnel chart configuration"""
        try:
            if x_col and y_col:
                # Group and sort data
                grouped = df.groupby(x_col)[y_col].sum().sort_values(ascending=False).head(10)
                data = [{'name': str(name), 'value': float(value)} for name, value in grouped.items()]
            else:
                # Use value counts
                cat_cols = df.select_dtypes(include=['object']).columns
                if len(cat_cols) > 0:
                    value_counts = df[cat_cols[0]].value_counts().head(8)
                    data = [{'name': str(name), 'value': int(value)} for name, value in value_counts.items()]
                else:
                    return {'error': True, 'message': 'Need categorical data for funnel chart'}
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'item',
                    'formatter': '{a} <br/>{b}: {c}'
                },
                'legend': {
                    'bottom': 10,
                    'left': 'center'
                },
                'series': [{
                    'name': 'Funnel',
                    'type': 'funnel',
                    'left': '10%',
                    'top': 60,
                    'bottom': 60,
                    'width': '80%',
                    'min': 0,
                    'max': max([item['value'] for item in data]) if data else 100,
                    'minSize': '0%',
                    'maxSize': '100%',
                    'sort': 'descending',
                    'gap': 2,
                    'label': {
                        'show': True,
                        'position': 'inside'
                    },
                    'itemStyle': {
                        'borderColor': '#fff',
                        'borderWidth': 1
                    },
                    'emphasis': {
                        'label': {
                            'fontSize': 20
                        }
                    },
                    'data': data
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def _create_multi_line_echarts(self, df: pd.DataFrame, columns: List[str], title: str) -> Dict:
        """Create multi-line chart for comparing multiple variables"""
        try:
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'axis',
                    'axisPointer': {'type': 'cross'}
                },
                'legend': {
                    'data': columns,
                    'bottom': 10
                },
                'grid': {
                    'left': '3%',
                    'right': '4%',
                    'bottom': '15%',
                    'containLabel': True
                },
                'xAxis': {
                    'type': 'category',
                    'data': df.index.tolist(),
                    'name': 'Index'
                },
                'yAxis': {
                    'type': 'value',
                    'name': 'Value'
                },
                'series': []
            }
            
            colors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452']
            
            for i, col in enumerate(columns):
                series_config = {
                    'name': col,
                    'type': 'line',
                    'data': df[col].tolist(),
                    'smooth': True,
                    'symbol': 'circle',
                    'symbolSize': 4,
                    'lineStyle': {'width': 2},
                    'itemStyle': {'color': colors[i % len(colors)]}
                }
                config['series'].append(series_config)
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}

    def _create_box_echarts(self, df: pd.DataFrame, column: str, title: str) -> Dict:
        """Create box plot for distribution analysis"""
        try:
            data = df[column].dropna()
            
            # Calculate box plot statistics
            q1 = data.quantile(0.25)
            q2 = data.quantile(0.5)  # median
            q3 = data.quantile(0.75)
            iqr = q3 - q1
            lower_whisker = max(data.min(), q1 - 1.5 * iqr)
            upper_whisker = min(data.max(), q3 + 1.5 * iqr)
            
            # Outliers
            outliers = data[(data < lower_whisker) | (data > upper_whisker)].tolist()
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'trigger': 'item',
                    'formatter': '{b}: {c}'
                },
                'grid': {
                    'left': '10%',
                    'right': '10%',
                    'bottom': '15%',
                    'containLabel': True
                },
                'xAxis': {
                    'type': 'category',
                    'data': [column],
                    'boundaryGap': True,
                    'nameGap': 30,
                    'splitArea': {'show': False},
                    'axisLabel': {'formatter': '{value}'},
                    'splitLine': {'show': False}
                },
                'yAxis': {
                    'type': 'value',
                    'name': 'Value',
                    'splitArea': {'show': True}
                },
                'series': [
                    {
                        'name': 'boxplot',
                        'type': 'boxplot',
                        'data': [[lower_whisker, q1, q2, q3, upper_whisker]],
                        'tooltip': {
                            'formatter': f'Min: {lower_whisker:.2f}<br/>Q1: {q1:.2f}<br/>Median: {q2:.2f}<br/>Q3: {q3:.2f}<br/>Max: {upper_whisker:.2f}'
                        }
                    },
                    {
                        'name': 'outlier',
                        'type': 'scatter',
                        'data': [[0, val] for val in outliers[:50]],  # Limit outliers for performance
                        'symbolSize': 4,
                        'itemStyle': {'color': '#d14a61'},
                        'tooltip': {
                            'formatter': 'Outlier: {c[1]}'
                        }
                    }
                ]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}

    def _create_advanced_heatmap_echarts(self, df: pd.DataFrame, title: str) -> Dict:
        """Create enhanced correlation heatmap with better visualization"""
        try:
            # Calculate correlation matrix
            numeric_df = df.select_dtypes(include=[np.number])
            if numeric_df.empty or len(numeric_df.columns) < 2:
                return {'error': True, 'message': 'Need at least 2 numeric columns for correlation matrix'}
            
            corr_matrix = numeric_df.corr()
            
            # Prepare data for heatmap
            data = []
            x_labels = list(corr_matrix.columns)
            y_labels = list(corr_matrix.index)
            
            for i, row_name in enumerate(y_labels):
                for j, col_name in enumerate(x_labels):
                    correlation = corr_matrix.loc[row_name, col_name]
                    data.append([j, i, round(correlation, 3)])
            
            config = {
                'title': {
                    'text': title,
                    'left': 'center',
                    'textStyle': {'fontSize': 16, 'fontWeight': 'bold'}
                },
                'tooltip': {
                    'position': 'top',
                    'formatter': lambda params: f'{y_labels[params["data"][1]]} vs {x_labels[params["data"][0]]}<br/>Correlation: {params["data"][2]}'
                },
                'grid': {
                    'height': '50%',
                    'top': '10%'
                },
                'xAxis': {
                    'type': 'category',
                    'data': x_labels,
                    'splitArea': {'show': True},
                    'axisLabel': {'rotate': 45}
                },
                'yAxis': {
                    'type': 'category',
                    'data': y_labels,
                    'splitArea': {'show': True}
                },
                'visualMap': {
                    'min': -1,
                    'max': 1,
                    'calculable': True,
                    'orient': 'horizontal',
                    'left': 'center',
                    'bottom': '15%',
                    'inRange': {
                        'color': ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
                    }
                },
                'series': [{
                    'name': 'Correlation',
                    'type': 'heatmap',
                    'data': data,
                    'label': {
                        'show': True,
                        'formatter': lambda params: str(params["data"][2])
                    },
                    'emphasis': {
                        'itemStyle': {
                            'shadowBlur': 10,
                            'shadowColor': 'rgba(0, 0, 0, 0.5)'
                        }
                    }
                }]
            }
            
            return config
            
        except Exception as e:
            return {'error': True, 'message': str(e)}
    
    def generate_chart(self, 
                      df: pd.DataFrame, 
                      chart_type: str, 
                      x_col: Optional[str] = None, 
                      y_col: Optional[str] = None, 
                      theme: str = 'seaborn',
                      title: str = '',
                      engine: str = 'matplotlib') -> str:
        """
        Generate chart and return as base64 encoded image (legacy method for compatibility)
        """
        if engine == 'plotly':
            return self._generate_plotly_chart(df, chart_type, x_col, y_col, title)
        else:
            return self._generate_matplotlib_chart(df, chart_type, x_col, y_col, theme, title)
    
    def _generate_matplotlib_chart(self, 
                                 df: pd.DataFrame, 
                                 chart_type: str, 
                                 x_col: Optional[str], 
                                 y_col: Optional[str], 
                                 theme: str, 
                                 title: str) -> str:
        """Generate chart using matplotlib/seaborn"""
        
        # Set theme
        if theme in self.themes:
            if theme == 'seaborn':
                sns.set_style("whitegrid")
                plt.style.use('default')
            else:
                plt.style.use(self.themes[theme])
        
        # Create figure
        fig, ax = plt.subplots(figsize=(10, 6))
        
        try:
            if chart_type == 'line':
                self._create_line_chart(df, x_col, y_col, ax)
            elif chart_type == 'bar' or chart_type == 'overview':
                self._create_bar_chart(df, x_col, y_col, ax)
            elif chart_type == 'scatter':
                self._create_scatter_chart(df, x_col, y_col, ax)
            elif chart_type == 'heatmap':
                self._create_heatmap(df, ax)
            elif chart_type == 'histogram':
                self._create_histogram(df, x_col, ax)
            elif chart_type == 'box':
                self._create_box_chart(df, x_col, y_col, ax)
            else:
                raise ValueError(f"Unsupported chart type: {chart_type}")
            
            # Set title and layout
            if title:
                ax.set_title(title, fontsize=14, fontweight='bold')
            
            plt.tight_layout()
            
            # Save to temporary file for Gradio
            import tempfile
            import os
            
            # Create temporary file
            temp_file = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
            temp_path = temp_file.name
            temp_file.close()
            
            # Save figure to file
            plt.savefig(temp_path, format='png', dpi=300, bbox_inches='tight')
            plt.close(fig)
            
            return temp_path
            
        except Exception as e:
            plt.close(fig)
            raise ValueError(f"Error generating chart: {str(e)}")
    
    def _generate_plotly_chart(self, 
                             df: pd.DataFrame, 
                             chart_type: str, 
                             x_col: Optional[str], 
                             y_col: Optional[str], 
                             title: str) -> str:
        """Generate interactive chart using plotly"""
        
        try:
            if chart_type == 'line':
                fig = px.line(df, x=x_col, y=y_col, title=title)
            elif chart_type == 'bar' or chart_type == 'overview':
                # For overview, create a bar chart
                if pd.api.types.is_object_dtype(df[x_col]) and pd.api.types.is_numeric_dtype(df[y_col]):
                    # Group categorical data
                    grouped_data = df.groupby(x_col)[y_col].mean().reset_index()
                    fig = px.bar(grouped_data, x=x_col, y=y_col, title=title)
                else:
                    fig = px.bar(df, x=x_col, y=y_col, title=title)
            elif chart_type == 'scatter':
                fig = px.scatter(df, x=x_col, y=y_col, title=title)
            elif chart_type == 'heatmap':
                corr_matrix = df.select_dtypes(include=[np.number]).corr()
                fig = px.imshow(corr_matrix, text_auto=True, aspect="auto", title=title)
            elif chart_type == 'histogram':
                fig = px.histogram(df, x=x_col, title=title)
            elif chart_type == 'box':
                fig = px.box(df, x=x_col, y=y_col, title=title)
            else:
                raise ValueError(f"Unsupported chart type: {chart_type}")
            
            # Save as static image for Gradio
            import tempfile
            import os
            
            # Create temporary file
            temp_file = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
            temp_path = temp_file.name
            temp_file.close()
            
            # Save as PNG image
            fig.write_image(temp_path, format='png', width=1000, height=600)
            
            return temp_path
            
        except Exception as e:
            raise ValueError(f"Error generating plotly chart: {str(e)}")
    
    def _create_line_chart(self, df: pd.DataFrame, x_col: str, y_col: str, ax):
        """Create line chart"""
        if x_col and y_col:
            df.plot(x=x_col, y=y_col, kind='line', ax=ax, marker='o')
        else:
            # Plot all numeric columns
            numeric_cols = df.select_dtypes(include=[np.number]).columns
            df[numeric_cols].plot(kind='line', ax=ax, marker='o')
        
        ax.set_xlabel(x_col or 'Index')
        ax.set_ylabel(y_col or 'Value')
    
    def _create_bar_chart(self, df: pd.DataFrame, x_col: str, y_col: str, ax):
        """Create bar chart"""
        if x_col and y_col:
            # If x is categorical and y is numeric, group and aggregate
            if df[x_col].dtype == 'object' and pd.api.types.is_numeric_dtype(df[y_col]):
                grouped_data = df.groupby(x_col)[y_col].mean()
                if len(grouped_data) > 20:  # Limit to top 20 categories
                    grouped_data = grouped_data.nlargest(20)
                grouped_data.plot(kind='bar', ax=ax)
            else:
                # Limit data points for readability
                plot_df = df.head(50) if len(df) > 50 else df
                plot_df.plot(x=x_col, y=y_col, kind='bar', ax=ax)
        else:
            # Group by first column if categorical
            if len(df.columns) >= 2:
                first_col = df.columns[0]
                second_col = df.columns[1]
                if df[first_col].dtype == 'object':
                    grouped_data = df.groupby(first_col)[second_col].mean()
                    if len(grouped_data) > 20:
                        grouped_data = grouped_data.nlargest(20)
                    grouped_data.plot(kind='bar', ax=ax)
                else:
                    plot_df = df.head(50) if len(df) > 50 else df
                    plot_df.plot(x=first_col, y=second_col, kind='bar', ax=ax)
        
        ax.set_xlabel(x_col or 'Category')
        ax.set_ylabel(y_col or 'Value')
        plt.xticks(rotation=45)
    
    def _create_scatter_chart(self, df: pd.DataFrame, x_col: str, y_col: str, ax):
        """Create scatter plot"""
        if x_col and y_col:
            # Sample data if too many points for performance
            plot_df = df.sample(min(5000, len(df))) if len(df) > 5000 else df
            
            # Remove null values
            plot_df = plot_df.dropna(subset=[x_col, y_col])
            
            if plot_df.empty:
                ax.text(0.5, 0.5, 'No valid data points', transform=ax.transAxes, ha='center')
                return
                
            ax.scatter(plot_df[x_col], plot_df[y_col], alpha=0.6, s=20)
            ax.set_xlabel(x_col)
            ax.set_ylabel(y_col)
            
            # Add trend line if both columns are numeric
            if pd.api.types.is_numeric_dtype(plot_df[x_col]) and pd.api.types.is_numeric_dtype(plot_df[y_col]):
                try:
                    z = np.polyfit(plot_df[x_col], plot_df[y_col], 1)
                    p = np.poly1d(z)
                    ax.plot(plot_df[x_col], p(plot_df[x_col]), "r--", alpha=0.8)
                except:
                    pass  # Skip trend line if calculation fails
        else:
            # Plot first two numeric columns
            numeric_cols = df.select_dtypes(include=[np.number]).columns
            if len(numeric_cols) >= 2:
                plot_df = df.sample(min(5000, len(df))) if len(df) > 5000 else df
                plot_df = plot_df.dropna(subset=[numeric_cols[0], numeric_cols[1]])
                
                if not plot_df.empty:
                    ax.scatter(plot_df[numeric_cols[0]], plot_df[numeric_cols[1]], alpha=0.6, s=20)
                    ax.set_xlabel(numeric_cols[0])
                    ax.set_ylabel(numeric_cols[1])
    
    def _create_heatmap(self, df: pd.DataFrame, ax):
        """Create correlation heatmap"""
        # Calculate correlation matrix for numeric columns
        numeric_df = df.select_dtypes(include=[np.number])
        if numeric_df.empty:
            raise ValueError("No numeric columns found for heatmap")
        
        corr_matrix = numeric_df.corr()
        sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0, 
                   square=True, ax=ax, fmt='.2f')
        ax.set_title('Correlation Heatmap')
    
    def _create_histogram(self, df: pd.DataFrame, x_col: str, ax):
        """Create histogram"""
        if x_col:
            # Remove null values
            data = df[x_col].dropna()
            
            if data.empty:
                ax.text(0.5, 0.5, 'No valid data', transform=ax.transAxes, ha='center')
                return
            
            # Determine optimal number of bins
            n_bins = min(50, max(10, len(data) // 20))
            
            if pd.api.types.is_numeric_dtype(data):
                data.hist(bins=n_bins, ax=ax, alpha=0.7, edgecolor='black')
            else:
                # For categorical data, create a count plot
                value_counts = data.value_counts().head(20)  # Top 20 categories
                value_counts.plot(kind='bar', ax=ax, alpha=0.7)
                plt.xticks(rotation=45)
                
            ax.set_xlabel(x_col)
        else:
            # Plot histogram of first numeric column
            numeric_cols = df.select_dtypes(include=[np.number]).columns
            if len(numeric_cols) > 0:
                data = df[numeric_cols[0]].dropna()
                if not data.empty:
                    n_bins = min(50, max(10, len(data) // 20))
                    data.hist(bins=n_bins, ax=ax, alpha=0.7, edgecolor='black')
                    ax.set_xlabel(numeric_cols[0])
        
        ax.set_ylabel('Frequency')
    
    def _create_box_chart(self, df: pd.DataFrame, x_col: str, y_col: str, ax):
        """Create box plot"""
        if x_col and y_col:
            df.boxplot(column=y_col, by=x_col, ax=ax)
        else:
            # Create box plot for all numeric columns
            numeric_cols = df.select_dtypes(include=[np.number]).columns
            if len(numeric_cols) > 0:
                df[numeric_cols].boxplot(ax=ax)
        
        ax.set_title('Box Plot')
    
    def get_suggested_chart_type(self, df: pd.DataFrame, x_col: str, y_col: str) -> str:
        """Suggest appropriate chart type based on data types"""
        if not x_col or not y_col:
            return 'histogram'
        
        x_dtype = df[x_col].dtype
        y_dtype = df[y_col].dtype
        
        # Both numeric -> scatter
        if pd.api.types.is_numeric_dtype(x_dtype) and pd.api.types.is_numeric_dtype(y_dtype):
            return 'scatter'
        
        # Categorical x, numeric y -> bar
        if pd.api.types.is_object_dtype(x_dtype) and pd.api.types.is_numeric_dtype(y_dtype):
            return 'bar'
        
        # Time series data -> line
        if pd.api.types.is_datetime64_any_dtype(x_dtype):
            return 'line'
        
        # Default
        return 'bar'
    
    def get_chart_recommendations(self, df: pd.DataFrame) -> Dict[str, Any]:
        """Get chart recommendations based on data characteristics"""
        numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()
        categorical_cols = df.select_dtypes(include=['object', 'category']).columns.tolist()
        datetime_cols = df.select_dtypes(include=['datetime']).columns.tolist()
        
        recommendations = {
            'suitable_charts': [],
            'column_suggestions': {
                'x_axis': [],
                'y_axis': []
            }
        }
        
        # Suggest charts based on column types
        if len(numeric_cols) >= 2:
            recommendations['suitable_charts'].extend(['scatter', 'line', 'heatmap', 'radar'])
        
        if len(categorical_cols) >= 1 and len(numeric_cols) >= 1:
            recommendations['suitable_charts'].extend(['bar', 'box', 'pie', 'funnel'])
        
        if len(numeric_cols) >= 1:
            recommendations['suitable_charts'].append('histogram')
        
        # Column suggestions
        recommendations['column_suggestions']['x_axis'] = categorical_cols + datetime_cols + numeric_cols
        recommendations['column_suggestions']['y_axis'] = numeric_cols
        
        return recommendations 